Reconciliation is the algorithm React uses to diff the virtual DOM tree with the previous one, generating a minimal set of DOM updates to apply, ensuring UI updates are efficient by batching changes and avoiding unnecessary re-renders.
Reconciliation is the core diffing algorithm in React that determines how to efficiently update the actual DOM when the application state changes. When a component's state or props change, React creates a new virtual DOM tree (a lightweight JavaScript representation of the UI) and compares it with the previous virtual DOM tree. The reconciliation process then calculates the minimal set of changes required to transform the old tree into the new one. These changes are batched and applied to the actual DOM in a single operation, avoiding costly direct DOM manipulations and ensuring that the UI stays responsive.
React's reconciliation is built on two key assumptions: components of the same type will produce similar tree structures, and elements with different types will produce completely different trees. Based on these assumptions, React uses a heuristic O(n) algorithm instead of a traditional O(n³) tree-diffing algorithm, making it practical for real-world applications. The process is orchestrated by the Fiber reconciler (introduced in React 16), which enables incremental rendering and prioritization of updates.
Different Element Types: If the root element types differ (e.g., <div> vs <span>), React tears down the old tree and builds a new one from scratch. This is a rare but fast operation.
Same Element Type: React compares attributes of DOM elements (className, style, etc.), updates only changed ones, and then recurses into children.
Component Instances: For component elements (function or class), React keeps the same instance and updates its props. The instance's lifecycle methods (componentWillReceiveProps, shouldComponentUpdate, etc.) are called, and render is invoked to get the new children.
Keys: Keys help React identify which items have changed, been added, or removed in lists. Using stable, unique keys (like item IDs) allows React to reorder elements instead of recreating them, dramatically improving performance for dynamic lists.
Before React 16, reconciliation was a synchronous, recursive process that could block the main thread for extended periods. The Fiber reconciler (introduced in React 16) re-implemented reconciliation as an interruptible, incremental process. Fiber breaks rendering work into units (fibers) and uses a priority system to schedule them. High-priority updates (like user input) can interrupt lower-priority work (like data fetching). This enables Concurrent Rendering features like useTransition and startTransition, allowing React to keep the UI responsive even during large updates.
Interruptible Work: Rendering can be paused, and work can be split across multiple frames.
Priority Levels: Updates are assigned priorities (Immediate, UserBlocking, Normal, Low, Idle).
Double Buffering: React maintains two trees—current (rendered to DOM) and workInProgress (being computed).
Commit Phase: Once reconciliation is complete, the changes are applied to the DOM in a single synchronous commit, ensuring consistency.
Concurrent Features: useTransition, useDeferredValue, and Suspense are built on Fiber's ability to handle partial rendering.
Reconciliation, combined with batching, dramatically reduces DOM operations. Instead of updating the DOM for every state change, React collects all changes during the reconciliation phase and applies them in a single batch. This avoids layout thrashing and ensures that the browser recalculates styles and layouts only once per update cycle. Additionally, React's use of keys allows efficient reordering of list items—instead of removing and re-inserting DOM nodes, React moves them, preserving their state (like input focus and selection).